﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.ConstrainedExecution;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using War3Trainer;

public class NetworkManager : IDisposable
{
    private const int BroadcastPort = 6066;
    private const int TcpPort = 6067;
    private readonly string _machineId;
    private readonly List<string> _knownMachines = new List<string>();
    private readonly List<Socket> _clientSockets = new List<Socket>();
    private Socket _serverSocket;
    private UdpClient _broadcastListener;
    private bool _isRunning;
    private readonly Action<string> _onUpdateReceived;
    private readonly string _localIpAddress;
    // 所有共享数据 key={machineName}:{ipAddress}
    public readonly Dictionary<string, HashSet<string>> SHARE_DATA = new Dictionary<string, HashSet<String>>();

    public NetworkManager(Action<string> onUpdateReceived)
    {
        _machineId = Dns.GetHostName();
        _onUpdateReceived = onUpdateReceived;
        _localIpAddress = GetLocalIPAddress();
    }

    public List<string> GetUnitAddressesByNameWithFilter(string name)
    {
        string filterStr = $"{GetMachineId()}:{GetLocalIPAddress()}";
        List<string> result = new List<string>();

        foreach (var kvp in SHARE_DATA)
        {
            string key = kvp.Key; // 格式：name:unitaddress

            // 过滤条件：只处理包含filterStr的key
            if (!key.Contains(filterStr))
                continue;

            // 遍历当前key对应的列表，查找符合条件的unitAddress
            foreach (var p in SHARE_DATA[key])
            {
                var parts = p.Split(':');
                if (parts.Length == 2 && parts[0] == name)
                {
                    result.Add(parts[1]);
                }
            }
        }

        return result;
    }

    public bool ExistAllShareClient(String name, ref String notFoundDevice)
    {
        name = name.Trim();
        foreach (var kvp in SHARE_DATA)
        {
            string key = kvp.Key;
            if (!SHARE_DATA[key].Any(s => s.StartsWith(name)))
            {
                notFoundDevice = key;
                return false;
            }
        }
        return true;
    }


    public String GetMachineId()
    {
        return _machineId;
    }

    public string GetLocalIPAddress()
    {
        var host = Dns.GetHostEntry(Dns.GetHostName());
        foreach (var ip in host.AddressList)
        {
            if (ip.AddressFamily == AddressFamily.InterNetwork)
            {
                return ip.ToString();
            }
        }
        throw new Exception("No network adapters with an IPv4 address in the system!");
    }

    public void Start()
    {
        if (_isRunning) return;

        _isRunning = true;

        Console.WriteLine($"Starting network manager on {_localIpAddress}");

        // Start TCP server
        _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _serverSocket.Bind(new IPEndPoint(IPAddress.Any, TcpPort));
        _serverSocket.Listen(10);
        new Thread(AcceptConnections) { IsBackground = true }.Start();

        // Start broadcast listener
        _broadcastListener = new UdpClient(BroadcastPort);
        new Thread(ListenForBroadcasts) { IsBackground = true }.Start();

        // Start broadcast sender
        new Thread(SendBroadcasts) { IsBackground = true }.Start();
    }

    private void AcceptConnections()
    {
        while (_isRunning)
        {
            try
            {
                Socket clientSocket = _serverSocket.Accept();
                var remoteIp = ((IPEndPoint)clientSocket.RemoteEndPoint).Address.ToString();
                Console.WriteLine($"Accepted connection from {remoteIp}");

                lock (_clientSockets)
                {
                    _clientSockets.Add(clientSocket);
                }
                new Thread(() => HandleClient(clientSocket)) { IsBackground = true }.Start();
            }
            catch (Exception ex)
            {
                if (_isRunning)
                    Console.WriteLine($"Accept error: {ex.Message}");
            }
        }
    }

    private void HandleClient(Socket clientSocket)
    {
        try
        {
            byte[] buffer = new byte[1024];
            List<byte> receivedData = new List<byte>();
            int expectedLength = -1;

            while (_isRunning)
            {
                int received = clientSocket.Receive(buffer);
                if (received == 0) break;

                // 累积数据
                receivedData.AddRange(new ArraySegment<byte>(buffer, 0, received));

                // 解析完整消息
                while (true)
                {
                    if (expectedLength == -1)
                    {
                        if (receivedData.Count >= 4)
                        {
                            expectedLength = BitConverter.ToInt32(receivedData.ToArray(), 0);
                            receivedData.RemoveRange(0, 4);
                        }
                        else
                        {
                            break; // 等待更多数据
                        }
                    }

                    if (expectedLength != -1 && receivedData.Count >= expectedLength)
                    {
                        byte[] messageBytes = receivedData.Take(expectedLength).ToArray();
                        receivedData.RemoveRange(0, expectedLength);
                        expectedLength = -1;

                        string message = Encoding.UTF8.GetString(messageBytes);
                        _onUpdateReceived?.Invoke(message);
                    }
                    else
                    {
                        break; // 等待更多数据
                    }
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Client handling error: {ex.Message}");
        }
        finally
        {
            lock (_clientSockets)
            {
                _clientSockets.Remove(clientSocket);
            }
            try { clientSocket.Close(); } catch { }
            Console.WriteLine("Client disconnected");
        }
    }

    private void ListenForBroadcasts()
    {
        IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, BroadcastPort);
        while (_isRunning)
        {
            try
            {
                byte[] data = _broadcastListener.Receive(ref remoteEP);
                string receivedData = Encoding.UTF8.GetString(data);
                Console.WriteLine($"Received broadcast: {receivedData}");

                Dictionary<string, Object> receiveDic = JsonConvert.DeserializeObject<Dictionary<string, Object>>(receivedData);
                String ipAddress = receiveDic["localIpAddress"].ToString();
                String machineName = receiveDic["machineId"].ToString();
                String localText = (ipAddress == _localIpAddress ? "(本机)" : "");

                // 将name和unitAddressHex同步过去 后面修改属性时 根据unitAddressHex将所有字段查出来
                String value = receiveDic["selected"]?.ToString();
                String key = $"{machineName}:{ipAddress}";
                if (!SHARE_DATA.TryGetValue(key, out var list))
                {
                    list = new HashSet<string>();
                    SHARE_DATA[key] = list;
                }
                if("clear" == value)
                {
                    SHARE_DATA.Clear();
                }
                if (null != value && "clear" != value)
                {
                    list.Add(value.Trim());
                }
                if (!_knownMachines.Contains(ipAddress))
                {
                    _knownMachines.Add(ipAddress);
                    ConnectToMachine(ipAddress);
                }
            }
            catch (Exception ex)
            {
                if (_isRunning)
                    Console.WriteLine($"Broadcast listen error: {ex.Message}");
            }
        }
    }

    private void ConnectToMachine(string ipAddress)
    {
        try
        {
            Console.WriteLine($"Attempting to connect to {ipAddress}");
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ipAddress), TcpPort));

            Console.WriteLine($"Connected to {ipAddress}");

            lock (_clientSockets)
            {
                _clientSockets.Add(clientSocket);
            }
            new Thread(() => HandleClient(clientSocket)) { IsBackground = true }.Start();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Connection to {ipAddress} failed: {ex.Message}");
        }
    }

    public void SendBroadcastsClearShareData()
    {
        using (UdpClient broadcaster = new UdpClient())
        {
            broadcaster.EnableBroadcast = true;
            IPEndPoint broadcastEP = new IPEndPoint(IPAddress.Broadcast, BroadcastPort);

            try
            {
                Dictionary<string, Object> broadcastDataDict = new Dictionary<string, Object>
                    {
                        { "localIpAddress", _localIpAddress },
                        { "machineId", _machineId },
                        { "selected",  "clear"}
                    };
                string broadcastJson = JsonConvert.SerializeObject(broadcastDataDict);
                string broadcastData = $"{broadcastJson}";
                byte[] data = Encoding.UTF8.GetBytes(broadcastData);

                broadcaster.Send(data, data.Length, broadcastEP);
                Console.WriteLine($"Sent clear broadcast: {broadcastData}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Broadcast send error: {ex.Message}");
            }
        }
    }

    public void SendBroadcastsWithSelected()
    {
        using (UdpClient broadcaster = new UdpClient())
        {
            broadcaster.EnableBroadcast = true;
            IPEndPoint broadcastEP = new IPEndPoint(IPAddress.Broadcast, BroadcastPort);

            try
            {
                String value = null;
                if (null != MainForm.selected)
                {
                    String name = MainForm.selected.Text?.Split(':')[1];
                    String unitAddressHex = MainForm.selected.Text?.Split(':')[0];
                    value = $"{name}:{unitAddressHex}";
                }
                Dictionary<string, Object> broadcastDataDict = new Dictionary<string, Object>
                    {
                        { "localIpAddress", _localIpAddress },
                        { "machineId", _machineId },
                        { "selected",  value}
                    };
                string broadcastJson = JsonConvert.SerializeObject(broadcastDataDict);
                string broadcastData = $"{broadcastJson}";
                byte[] data = Encoding.UTF8.GetBytes(broadcastData);

                broadcaster.Send(data, data.Length, broadcastEP);
                Console.WriteLine($"Sent selected broadcast: {broadcastData}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Broadcast send error: {ex.Message}");
            }
        }
    }

    public void SendBroadcasts()
    {
        using (UdpClient broadcaster = new UdpClient())
        {
            broadcaster.EnableBroadcast = true;
            IPEndPoint broadcastEP = new IPEndPoint(IPAddress.Broadcast, BroadcastPort);

            while (_isRunning)
            {
                try
                {
                    // 构造通用的基础数据
                    var baseData = new Dictionary<string, Object>
                    {
                        { "localIpAddress", _localIpAddress },
                        { "machineId", _machineId }
                    };


                    if (SHARE_DATA.Count > 0)
                    {
                        string key = $"{GetMachineId()}:{GetLocalIPAddress()}";

                        if (SHARE_DATA.TryGetValue(key, out var list) && list != null && list.Count > 0)
                        {
                            foreach (var item in list)
                            {
                                // 复制基础数据，加入当前item
                                var broadcastDataDict = new Dictionary<string, Object>(baseData)
                            {
                                { "selected", item }
                            };
                                SendBroadcast(broadcaster, broadcastDataDict, broadcastEP);
                            }
                        }
                        else
                        {
                            // 如果没有找到，仍然可以选择不发或者发空数据，这里选择发空
                            var broadcastDataDict = new Dictionary<string, Object>(baseData)
                        {
                            { "selected", null }
                        };
                            SendBroadcast(broadcaster, broadcastDataDict, broadcastEP);
                        }
                    }
                    else
                    {
                        // SHARE_DATA为空，发送带null的广播
                        var broadcastDataDict = new Dictionary<string, Object>(baseData)
                    {
                        { "selected", null }
                    };
                        SendBroadcast(broadcaster, broadcastDataDict, broadcastEP);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Broadcast send error: {ex.Message}");
                }

                Thread.Sleep(5000);
            }
        }
    }

    // 封装广播发送的逻辑
    private void SendBroadcast(UdpClient broadcaster, Dictionary<string, Object> dataDict, IPEndPoint ep)
    {
        string json = JsonConvert.SerializeObject(dataDict);
        byte[] data = Encoding.UTF8.GetBytes(json);
        broadcaster.Send(data, data.Length, ep);
        Console.WriteLine($"Sent broadcast: {json}");
    }

    public void BroadcastUpdate(string updateMessage)
    {
        byte[] messageBytes = Encoding.UTF8.GetBytes(updateMessage);
        byte[] lengthBytes = BitConverter.GetBytes(messageBytes.Length); // 4字节长度

        byte[] data = new byte[lengthBytes.Length + messageBytes.Length];
        Buffer.BlockCopy(lengthBytes, 0, data, 0, lengthBytes.Length);
        Buffer.BlockCopy(messageBytes, 0, data, lengthBytes.Length, messageBytes.Length);

        lock (_clientSockets)
        {
            foreach (var socket in _clientSockets.ToArray())
            {
                try
                {
                    socket.Send(data);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Update send error: {ex.Message}");
                }
            }
        }
    }

    public void Dispose()
    {
        if (!_isRunning) return;

        _isRunning = false;
        Console.WriteLine("Shutting down network manager...");

        try { _broadcastListener?.Close(); } catch { }
        try { _serverSocket?.Close(); } catch { }

        lock (_clientSockets)
        {
            foreach (var socket in _clientSockets)
            {
                try { socket.Close(); } catch { }
            }
            _clientSockets.Clear();
        }
    }
}
